#ifndef XGE_XWORKER_PRIORITY_QUEUE_H_
#define XGE_XWORKER_PRIORITY_QUEUE_H_
#include "xge_common_config.h"
#include "xassert.h"
#include "xworker_queue.h"
#include "xsync.h"
#include "xdata_structure.h"
#include "xallocator.h"
#include "xloop_sync.h"
#include "xstring.h"
#include "xpriority_task.h"


//$ Revision: 2011/12/23
// 1. Delete the interface Terminate , the reason is in xworker_queue file
//$

//$ Revision: 2011/12/24
// 1. Change the mechanism to implement the PostQuitSoon and PostQuitWhenEmpty 
//    We use a specialized Task to indicate the PostQuitSoon and PostQuitWhenEmpty message
// 2. Delete the interface for the single dequeue operation , I turn all the task fetch operation
//    to the vector version , means the Dequeue will automatically decide how much task fetch at once!
//$

namespace xge{
namespace xge_internal{

  // A single priority queue
  // this queue will be implemented using STL::priority_queue , namely a vector with min-heap-sort algorithm 
  // so the sorting complexity is about o(logN*N) , every erase will be using time (logN)
  // so it is comparatively slow , however , we have many types of queue , you can switch to other suitable queue

  class WorkerPriorityQueue : public WorkerQueue , private LoopSync  {
  public:
    // Ctor 
    inline WorkerPriorityQueue ();
    // Dtor
    inline ~WorkerPriorityQueue();
  public:
    typedef WorkerQueue::TaskPtrList TaskPtrList;
    // Push task into the queue 
    // If the task_ptr is in fact not a suitable task 
    // the push operation will be failed
    // otherwise , it will succeed
    virtual bool PushTask   ( const TaskPtr& task_ptr   );
    virtual bool TryPushTask( const TaskPtr& task_ptr   );
    virtual size_t PushTask ( TaskPtrList* task_ptr_list );

    // WaitWhenRelease 
    virtual const TripleResult WaitWhenRelease( int ms );
    virtual bool WaitWhenRelease();
    // WaitWhenEmpty
    virtual bool WaitWhenEmpty();
    virtual const TripleResult WaitWhenEmpty( int ms );
      
  public:
    // the queue loop 
    virtual int Loop() ;
    // post to this queue to exit soon 
    inline virtual void PostQuitSoon();
    inline virtual void PostQuitWhenEmpty();
    inline void Clear();

  public:
    // how many task store in the queue
    size_t size() const {
      return queue_.size();
    }

    bool empty() const {
      return queue_.empty();
    }

    PriorityTask::priority_t cur_max_priority() const {
      return cur_max_priority_;
    }

  private:
    // container for multi-task-ptr 
    typedef xge::vector< TaskPtr >::Vector TaskPtrVector;
    // This function is Dequeue however , it pick at least n element in the queue( if it have at most n )
    // This function is preferred for the Loop to do the pre-fetch operation to avoid the delete task over head
    size_t Dequeue( TaskPtrVector* container , size_t size );
    // Wake up the back queue
    inline void WakeUp();
  private:
    // Loop sync call back function 
    // We do the adjusting stuff here .
    // Basically , we won't use diff_time , we just 
    // use loop times to do the audition 
    // We will calculate the delete calling times per-loop and we
    // get enough information to do the precache optimizing for the
    // Main Task Loop .
    inline virtual void LoopTicking( const Timer::tick_t& diff_time );
    // Clear all the worker task in the thread 
    void ClearQueue();
    // Push the message into the queue for Quit and QuitEmpty
    bool PushMessage( const TaskPtr& task_ptr );
  private:
    // A priority task message 
    class PriorityMessage : public PriorityTask {
    public:
      PriorityMessage( PriorityTask::priority_t priority , const String& msg_val ) :
          PriorityTask(priority,REMOTE_MESSAGE,msg_val){}
      virtual void Execute() {}
    };
    // This is fast-lock( namely the Critical Section on windows )
    // I use this for the queue synchronizations locking since it is fast
    FastLock queue_sync_lock_;
    // This is the signal synchronizations lock
    // this is used as a mechanism to wake up the thread when thread sleep
    WaitableEvent waitable_event_;
    // This is proxy store in the priority_queue
    struct SPriorityProxy {
      // This ptr is used to store the XTaskPtr
      TaskPtr task_ptr;
      bool operator < ( const SPriorityProxy& inst ) const {
        return task_ptr->DownCast<PriorityTask>()->priority() < inst.task_ptr->DownCast<PriorityTask>()->priority();
      }
      SPriorityProxy( const TaskPtr& ptr ) : task_ptr(ptr) {}

    };
    //define the task priority queue
    typedef xge::priority_queue< SPriorityProxy >::PriorityQueue XTaskQueue;
    // this queue is the internal queue for storing the task 
    XTaskQueue queue_;
    // some other audition record for the real time scheduling
    // recording the enqueue operation times
    // if the enqueue happens a lot the corresponding precache operation will be used 
    // this is dynamically 
    size_t enqueue_times_totally_ ;
    // This is the record of the loop times 
    uint64_t loop_times_;
    // This is the precache task size
    size_t precache_size_;
    // since we have make the LoopSync as the private function 
    // so we have to make XLoopSync as a friend class to avoid compiler error
    friend class LoopSync;
    // record the current max priority 
    PriorityTask::priority_t cur_max_priority_;
    // Some const char
    static const char_t* kAboutToQuit ;
    static const char_t* kQuitEmpty   ;
    static const size_t kMaxPrecacheSize = 5;
    DISALLOW_COPY_AND_ASSIGN(WorkerPriorityQueue);

  };

  inline WorkerPriorityQueue::WorkerPriorityQueue() : 
    enqueue_times_totally_(0),
    loop_times_(0u),
    precache_size_(1),
    cur_max_priority_(PriorityTask::GetMinPriority()),
    waitable_event_(false), // auto reset waitable event
    WorkerQueue(WorkerQueue::QUEUE_TYPE_PRIROITY_QUEUE,REMOTE_BINDING){
    }

  inline WorkerPriorityQueue::~WorkerPriorityQueue() {
    // This deletion is a little bit fancy 
    ClearQueue();
  }

  inline void WorkerPriorityQueue::Clear() {
    queue_sync_lock_.Lock();
    ClearQueue();
    queue_sync_lock_.Unlock();
  }


  inline void WorkerPriorityQueue::PostQuitSoon() {
    // Revision of his post quit soon
    // 1. We just push a message into the queue and set it to the max priority
    // however , if we fail to push the message
    // that means we have push a message into the queue before , so we simply return
    PushMessage(TaskPtr( new PriorityMessage(cur_max_priority_,kAboutToQuit)));
  }

  inline void WorkerPriorityQueue::PostQuitWhenEmpty() {
    // Revision of this post quit when empty
    PushMessage(TaskPtr( new PriorityMessage(cur_max_priority_,kQuitEmpty)));
  }

  inline void WorkerPriorityQueue::WakeUp() {
    waitable_event_.Notify();
  }

  inline void WorkerPriorityQueue::LoopTicking( const Timer::tick_t& diff_time ) {
    // we assume the loop average task push will happen 10 times average
    static const size_t kLoopAdjustCoefficient = 10 ;
    // now check the last average loop enqueue times 
    ++loop_times_;
    size_t average_val = (size_t)( enqueue_times_totally_ /(loop_times_*kLoopAdjustCoefficient) ) ;
    if( average_val > kMaxPrecacheSize ) 
      average_val = kMaxPrecacheSize;
    if( average_val != 0 ) {
      precache_size_ = average_val;
    }
    // ok now
  }

}//namespace xge_internal
}//namespace xge

#endif// XGE_XWORKER_PRIORITY_QUEUE_H_